#include "PrecompiledHeader_Engineer.h"
#include "Quad.h"

/*--------------------------------------------------------------------------*/

Quad::Quad(const glm::vec2& startPos)
{
	this->m_smallStuff = NULL;
	this->m_smallStuffCount = 0;

	this->m_fireplaces = NULL;
	this->m_fireplacesLights = NULL;
	this->m_fireplacesCount = 0;

	this->m_startPos = startPos;

	unsigned int width = 51;
	unsigned int height = 51;

	this->m_terrainVao = new VertexArray(3);

	glm::vec3* verts = new glm::vec3[height * width];
	glm::vec3* normal = new glm::vec3[height * width];
	glm::vec2* texcor = new glm::vec2[height * width];

	int counter = 0;

	for (unsigned int y = 0; y < height; ++y)
	{
		for (unsigned int x = 0; x < width; ++x)
		{
			texcor[counter].x = (float) x / (float)(width - 1);
			texcor[counter].y = (float) y / (float)(height - 1);

			verts[counter].x = (float) x / (float)(width - 1);
			verts[counter].y = (float) y / (float)(height - 1);
			verts[counter].z = 0.5f;

			verts[counter] = (verts[counter] - glm::vec3(0.5f)) * CWorld::m_quadSize;

			glm::vec3 tmp = glm::vec3(verts[counter].x + startPos.x, verts[counter].y + startPos.y, 0.0f);

			WTerrain::getInstance()->GetHeight(tmp);
			verts[counter].z = tmp.z;

			WTerrain::getInstance()->GetNormal(tmp, normal[counter]);

			++counter;
		}
	}

	unsigned int* indices = new unsigned int[width * height + (width - 1) * (height - 2)];
	int c = 0;

	for (unsigned int row = 0; row < height - 1; ++row)
	{
		if ((row % 2) == 0)   // even rows
		{
			for (unsigned int col = 0; col < width; ++col)
			{
				indices[c++] = col + row * width;
				indices[c++] = col + (row + 1) * width;
			}
		}
		else   // odd row
		{
			for (unsigned int col = width - 1; col > 0; --col)
			{
				indices[c++] = col + (row + 1) * width;
				indices[c++] = col - 1 + row * width;
			}
		}
	}

	if ((height & 1) && height > 2)
	{
		indices[c] = (height - 1) * width;
	}

	this->m_terrainVao->SetData((float*) verts, width * height, 0, 3);
	this->m_terrainVao->SetData((float*) normal, width * height, 1, 3);
	this->m_terrainVao->SetData((float*) texcor, width * height, 2, 2);

	this->m_terrainVao->SetIndices(indices, width * height + (width - 1) * (height - 2), GL_TRIANGLE_STRIP);

	delete [] indices;
	delete [] verts;
	delete [] texcor;
	delete [] normal;

	this->SetLowQualityVao(this->m_terrainVao);
	this->SetHighQualityVao(this->m_terrainVao);
	this->SetOcclusionTestEnabled(false);

	this->ClearTasks();
	this->AddRenderTask(CContext::getInstance()->GetContext("d3d_terrain"),
	                    CMaterial::getInstance()->GetMaterial("mat_3d_terrain"),
	                    CCamera::getInstance()->GetCamera("cam3d"),
	                    10,
	                    vl::Render::ColorAndDepth);

	std::stringstream ss;
	ss << startPos.x << " x " << startPos.y << " @ " << this;
	this->SetName(ss.str());

	this->SetPosition(glm::vec3(startPos.x, startPos.y, 0.0f));
	this->SetScale(1.0f);
	this->SetRadius(CWorld::m_quadSize * glm::sqrt(2.0f) * 0.5f);

	this->AddSomeSmallStuff();
}

/*--------------------------------------------------------------------------*/

Quad::~Quad()
{
	delete this->m_terrainVao;
}

/*--------------------------------------------------------------------------*/

void Quad::QuadStart()
{
	this->SetParent(CTree::getInstance()->GetRoot());
}

/*--------------------------------------------------------------------------*/

void Quad::QuadStop()
{
	this->RemoveFromTree();
}

/*--------------------------------------------------------------------------*/

void Quad::AddSomeSmallStuff()
{
	Mesh* trees[5];
	CResources::getInstance()->Get("tree1", &(trees[0]));
	CResources::getInstance()->Get("tree2", &(trees[1]));
	CResources::getInstance()->Get("tree3", &(trees[2]));
	CResources::getInstance()->Get("tree4", &(trees[3]));
	CResources::getInstance()->Get("tree5", &(trees[4]));

	unsigned int treesC = 10 + rand() % 8;

	for (unsigned int i = 0; i < treesC; ++i)
	{
		glm::vec3 r = glm::vec3(rand() % 100 / 100.0f - 0.5f, rand() % 100 / 100.0f - 0.5f, 0.0f) * CWorld::m_quadSize;
		glm::vec3 p = r + glm::vec3(this->m_startPos.x, this->m_startPos.y, 0.0f);
		WTerrain::getInstance()->GetHeight(p);
		r.z = p.z;

		if ((rand() % 255) / 255.0f < WTerrain::getInstance()->GetJunglePropability(p))
		{
			if (r.z > 6.0f)
			{
				MeshInstance* m = trees[rand() % 5]->CreateInstance();
				m->SetName("tree");
				m->SetScale(15.0f + rand() % 12);
				m->SetRadius(m->GetScale().x);
				m->SetParent(this);
				m->SetPosition(r);
				m->SetRotation(glm::vec3(0.0f, 0.0f, rand() % 360));
			}
		}
	}

	Mesh* rock;
	CResources::getInstance()->Get("rock", &rock);

	unsigned int rocksC = 5 + rand() % 50;

	for (unsigned int i = 0; i < rocksC; ++i)
	{
		glm::vec3 r = glm::vec3(rand() % 100 / 100.0f - 0.5f, rand() % 100 / 100.0f - 0.5f, 0.0f) * CWorld::m_quadSize;
		glm::vec3 p = r + glm::vec3(this->m_startPos.x, this->m_startPos.y, 0.0f);
		WTerrain::getInstance()->GetHeight(p);
		r.z = p.z;

		if ((rand() % 255) / 255.0f < WTerrain::getInstance()->GetJunglePropability(p))
		{
			MeshInstance* m = rock->CreateInstance();
			m->SetName("rock");
			m->SetScale(1.0f + (rand() % 8) / 8.0f);
			m->SetRadius(m->GetScale().x);
			m->SetParent(this);
			m->SetPosition(r);
			m->SetRotation(glm::vec3(rand() % 360, rand() % 360, rand() % 360));

			//this->m_collideableObjects.push_back(m);
		}
	}

	Mesh* plants[2];
	CResources::getInstance()->Get("plant1", &(plants[0]));
	CResources::getInstance()->Get("plant1", &(plants[1]));

	unsigned int plantsC = 10 + rand() % 10;

	for (unsigned int i = 0; i < plantsC; ++i)
	{
		glm::vec3 r = glm::vec3(rand() % 100 / 100.0f - 0.5f, rand() % 100 / 100.0f - 0.5f, 0.0f) * CWorld::m_quadSize;
		glm::vec3 p = r + glm::vec3(this->m_startPos.x, this->m_startPos.y, 0.0f);
		WTerrain::getInstance()->GetHeight(p);
		r.z = p.z;

		if ((rand() % 255) / 255.0f < WTerrain::getInstance()->GetJunglePropability(p))
		{
			if (r.z < 3.0f && r.z > 2.0f)
			{
				r.z = 3.0f;
			}

			if (r.z >= 3.0f)
			{
				MeshInstance* m = plants[rand() % 2]->CreateInstance();
				m->SetName("plants");
				m->SetScale(2.0f + rand() % 1);
				m->SetRadius(m->GetScale().x);
				m->SetParent(this);
				m->SetPosition(r);
				m->SetRotation(glm::vec3(0.0f, 0.0f, rand() % 360));
			}
		}
	}
}

/*--------------------------------------------------------------------------*/

void Quad::TreeCalc()
{
	__super::TreeCalc();
}

/*--------------------------------------------------------------------------*/

bool Quad::IsCollision(const glm::vec2& pos)
{
	for (std::vector<IObject*>::iterator iter = this->m_collideableObjects.begin(); iter != this->m_collideableObjects.end(); ++iter)
	{
		glm::vec2 ip = glm::vec2((*iter)->GetPosition().x, (*iter)->GetPosition().y);

		if (glm::distance(pos, ip) < (*iter)->GetRadius()  * 0.5f)
		{
			return true;
		}
	}

	return false;
}

/*--------------------------------------------------------------------------*/